/*
 * scanner.h
 *
 *  Created on: 2010-10-15
 *      Author: tom
 */

#ifndef SCANNER_H_
#define SCANNER_H_

#include <fstream>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include "global.h"
#include "token.h"
using std::ios;
using std::ifstream;
using std::string;
using std::vector;
using std::cout;

class Scanner{
public:
	Scanner(char* path){
		ifstream* input=new ifstream(path,ios::in);
		char ch;        //ch is the current character in the file

		for(ch=input->get();ch!=EOF;ch=input->get())
			content+=ch;

		delete input;
	}

	void scan(vector<Token*>& token){
		string::const_iterator current;
		int state;

		for(current=content.begin();current<content.end()-2;current++){
			state=0;
			string currentToken;

			while(transition[state][lineNum(*current)]!=-1&&current<content.end()-2){                  //table-driven
				state=transition[state][lineNum(*current)];
				currentToken+=*current;
				current++;
			}

			switch(state){
				case 0:{                                             //the currentToken is '}'
					token.push_back(new Erro(currentToken));
					break;
				}
				case 1:{
					if(find(keyword.begin(),keyword.end(),currentToken)==keyword.end())
						token.push_back(new Id(currentToken));
					else
						token.push_back(new Key(currentToken));
					current--;
					break;
				}
				case 2:{
					token.push_back(new Num(currentToken));
					current--;
					break;
				}
				case 3:{                                        //the currentToken is a whitespace
					current--;
					break;
				}
				case 4:{
					cout<<"Missing \'\n";
					current--;
					break;
				}
				case 5:{
					currentToken.assign(currentToken.begin()+1,currentToken.end()-1);
					if(find(currentToken.begin(),currentToken.end(),'\n')==currentToken.end()||find(currentToken.begin(),currentToken.end(),static_cast<char>(13))==currentToken.end())
						cout<<"The String \""<<currentToken<<"\" Has More Than A Line\n";
					else
						token.push_back(new Str(currentToken));
					current--;
					break;
				}
				case 6:{
					cout<<"Missing }\n";
					break;
				}
				case 7:{                                 //the currentToken is a comment
					current--;
					break;
				}
				case 8:{
					if(find(specialSymbol.begin(),specialSymbol.end(),currentToken)!=specialSymbol.end())
						token.push_back(new Sym(currentToken));
					else
						token.push_back(new Erro(currentToken));
					current--;
					break;
				}
			}
		}

	}

private:
	int lineNum(char ch){
		if(('a'<=ch&&ch<='z')||('A'<=ch&&ch<='Z'))
			return 0;
		if(static_cast<char>(48)<=ch&&ch<=static_cast<char>(57))                  //ch is a symbol
			return 1;
		if(ch=='\n'||ch=='\t'||ch==' '||ch==static_cast<char>(13))                //ch is a whitespace
			return 2;
		if(ch=='{')
			return 3;
		if(ch=='}')
			return 4;
		if(ch=='\'')
			return 5;
		else
			return 6;
	}
	string content;                //content is the string variable that stores the file's content
};
	double hello;

#endif /* SCANNER_H_ */
